/*
 * Copyright (C) 2010 Fores Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package jp.fores.midori.client.handler;

import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.zip.GZIPOutputStream;

import jp.fores.midori.client.RPCClient;
import jp.fores.midori.core.dto.RPCInputDto;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.entity.ContentProducer;

/**
 * 入力データ用のDTOの内容を出力ストリーム経由でEntityに出力するためのクラス。<br>
 * (内部処理用のクラスなので、あえてパッケージスコープで定義しています。)<br>
 */
class InternalContentProducer implements ContentProducer {
	//==========================================================
	//定数

	/**
	 * ログ出力用
	 */
	private static final Log log = LogFactory.getLog(InternalContentProducer.class);

	/**
	 * バッファサイズ
	 */
	private static final int BUFFER_SIZE = 8192;


	//==========================================================
	//フィールド

	/**
	 * リモートプロシージャーコール用を行うクライアント
	 */
	private final RPCClient rpcClient;

	/**
	 * 入力データ用のDTO
	 */
	private final RPCInputDto inputDto;


	//==========================================================
	//メソッド

	//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
	//コンストラクタ

	/**
	 * コンストラクタです。<br>
	 *
	 * @param rpcClient リモートプロシージャーコール用を行うクライアント
	 * @param inputDto 入力データ用のDTO
	 */
	public InternalContentProducer(RPCClient rpcClient, RPCInputDto inputDto) {
		//==========================================================
		//引数の値をフィールドに設定

		//リモートプロシージャーコール用を行うクライアント
		this.rpcClient = rpcClient;

		//入力データ用のDTO
		this.inputDto = inputDto;
	}


	//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
	//抽象メソッドの実装

	/**
	 * 出力ストリームへの書き込みを行います。<br>
	 *
	 * @param outputStream 出力ストリーム
	 * @throws IOException 入出力エラーが発生した場合
	 */
	@Override
	public void writeTo(OutputStream outputStream) throws IOException {
		try {
			//リクエスト送信時にgzip圧縮を行う場合
			if (this.rpcClient.requestGZip) {
				//デバッグログが有効な場合
				if (log.isDebugEnabled()) {
					//デバッグログ出力
					log.debug("リクエスト送信時にgzip圧縮を行います。");
				}

				//出力ストリームをGZIPOutputStreamでラッピングする
				outputStream = new GZIPOutputStream(outputStream);
			}
			//それ以外の場合
			else {
				//出力ストリームをBufferedOutputStreamでラッピングする
				outputStream = new BufferedOutputStream(outputStream, BUFFER_SIZE);
			}

			//RPCの入力データを格納するためのDTOクラスの内容を、出力ストリームに出力する
			//(サーバーに入力データを送る)
			//(rpcClientの中のserializerに処理を委譲する)
			this.rpcClient.serializer.inputDtoToOutputStream(this.inputDto, outputStream);
		}
		//例外処理
		catch (Exception e) {
			//このメソットではIOExceptionしか投げられないので、捕捉した例外をIOExceptionでラッピングして投げ直す
			throw new IOException(e.getMessage());
		}
		//終了処理
		finally {
			//出力ストリームを確実に閉じる
			//(ここで出力ストリームを閉じなくても、入力ストリームを開こうとすると自動的に閉じられるようだが、念のために閉じておく)
			if (outputStream != null) {
				try {
					outputStream.close();
				}
				//例外処理
				catch (Exception e) {
					//どうしようもないので、例外はもみ消す
				}
			}
		}
	}

}
